/*
 * Layer.h
 *
 *  Created on: 2010-10-25
 *      Author: wenjian
 */

#ifndef LAYER_H_
#define LAYER_H_
#include "../commons.h"
#include <wingdi.h>
#include <GdiPlus.h>
#include "../draw/AbstractLayer.h"

namespace Ed {
  class AbstractDrawPage;
  class Element;
  class Selection;

  class Layer: public AbstractLayer {
    public:
      Layer(AbstractDrawPage* page, Selection* selct=NULL);
      virtual ~Layer();

      /**
       * 设置层相对画布位置(x,y)坐标，宽度，高度
       */
      virtual inline void setGeometry(real x, real y, real w, real h){
        if(geometry.Width != w || geometry.Height != h){
          destroyDoubleBuffer();
        }
        geometry.X = x;
        geometry.Y = y;
        geometry.Width = w;
        geometry.Height = h;
        setModified(true);
      }

      /**
       * 设置层相对画布位置(x,y)坐标，宽度，高度
       */
      virtual inline void setGeometry(const Gdiplus::RectF& rect){
        setGeometry(rect.X, rect.Y, rect.Width, rect.Height);
      }

      /**
       * 返回层相对画布位置(x,y)坐标，宽度，高度
       */
      virtual inline const Gdiplus::RectF& getGeometry() const{
        return geometry;
      }

      /**
       * 检查是否包含点(x, y)
       */
      virtual inline bool intersects(real x, real y){
        return geometry.Contains(x, y);
      }

      /**
       * 返回x坐标
       */
      virtual inline real x() const{
        return geometry.X;
      }
      /**
       * 返回y坐标
       */
      virtual inline real y() const{
        return geometry.Y;
      }

      /**
       * 返回宽度
       */
      virtual inline real width() const{
        return geometry.Width;
      }

      /**
       * 返回高度
       */
      virtual inline real height() const{
        return geometry.Height;
      }

      /**
       * 画图层
       */
      virtual void draw(Gdiplus::Graphics* g);

      /**
       * 返回选择区域中除<code>excludeds</code>以外的所有相交的元素, 在<code>v</code>中返回相交的元素，<code>rects</code>为指定的区域集。
       * <code>excludeds</code>更优先于<code>appendeds</code>。注意：excludeds和appendeds在调用此方法前必须排序
       *
       *
       * @param excludeds 为被排除的元素
       * @param appendeds 中为附加的元素，即使appendeds中的元素没有在相交区域，也将此附加元素在<code>v</code>中返回，
       *                  这样的目的主要是为了能返回拥有正确层次的元素
       *
       */
      virtual vector<Element*>* getIntersectionElements(vector<Element*>* v, const vector<const Gdiplus::RectF*>* rects, const vector<Element*>* excludeds=NULL, const vector<Element*>* appendeds=NULL);

      virtual vector<Element*>* getIntersectionElements(vector<Element*>* v, const Gdiplus::RectF* r, const vector<Element*>* excludeds=NULL, const vector<Element*>* appendeds=NULL);

      virtual vector<Element*>* getIntersectionElements(vector<Element*>* v, Element* el, const vector<Element*>* excludeds=NULL, const vector<Element*>* appendeds=NULL);

      virtual vector<Element*>* getIntersectionElements(vector<Element*>* v,  const vector<Element*>* intersEls, const vector<Element*>* excludeds=NULL, const vector<Element*>* appendeds=NULL);

      /**
       * 检查此元素是否在可视区
       */
      virtual bool enableDisplay(Element* e);

      /**
       * 合并重画区域
       */
      virtual void unionDrawRegion(const Gdiplus::RectF* rect);

      /**
       * 设置背景
       */
      virtual void setBackground(const Gdiplus::Color& c);

      /**
       * 返回背景
       */
      virtual const Gdiplus::Color& getBackground();

      /**
       * 返回层中所有元素
       */
      virtual inline const std::vector<Element*>* getElements() const{
        return (const std::vector<Element*>*)elements.getAbstractElements();
      }

      /**
       * 返回选择器
       */
      virtual inline Selection* getSelection(){
        return (Selection*)selection;
      }

      /**
       * 对ordereds中中元素排序，排序规则与元素在层中的顺序一致
       */
      virtual void sortElements(std::vector<Element*>* ordereds){
        AbstractLayer::sortElements((std::vector<AbstractElement*>*)ordereds);
      }

      /**
       * 在outOrdereds中返回inOrdereds被排序后的元素，排序规则与元素在层中的顺序一致
       */
      virtual void sortElements(std::vector<Element*>* outOrdereds, const std::vector<Element*>* inOrdereds){
        AbstractLayer::sortElements((std::vector<AbstractElement*>*)outOrdereds, (const std::vector<AbstractElement*>*)inOrdereds);
      }


      /**
       * 设置重画所有元素标记
       */
      virtual void setRedrawAll(){
        redrawAllFlag = true;
      }

    private:
      /**
       * 仅绘制被修改的可视元素
       */
      void drawRegion(Gdiplus::Graphics* g);
      /**
       * 绘制所有可视元素
       */
      void drawAll(Gdiplus::Graphics* g);

      /**
       * 画元素
       */
      void drawElement(Element* e, Gdiplus::Graphics* g);

    protected:
      //层在画布上的相对位置
      Gdiplus::RectF geometry;

      /**
       * 创建双缓冲
       */
      virtual void createDoubleBuffer();

      /**
       * 销毁双缓冲
       */
      virtual void destroyDoubleBuffer();

      /**
       * 销毁重画区域
       */
      virtual void destroyDrawRegion();

      /**
       * 剪切绘图区域
       */
      virtual void clipDrawRegion(Gdiplus::Graphics* g);

      /**
       * 复位被剪切的绘图区域
       */
      virtual void resetClipedDrawRegion(Gdiplus::Graphics* g);

      virtual bool isRedrawAll(){
        if(redrawAllFlag){
          redrawAllFlag = false;
          return true;
        }
        return false;
      }

    private:
      typedef vector<Element*>::iterator Iterator;
      typedef vector<Element*>::const_iterator ConstIterator;
      //默认选择器
      Selection* defaultSelection;
      //重画区域
      Gdiplus::Region* clipedRegion;
//      Gdiplus::GraphicsPath* clipedRegion;
      //背景颜色
      Gdiplus::Color background;
      //重画所有元素标记, 一旦检查了此标记后，此标记将自动复位
      bool redrawAllFlag;
  };

}

#endif /* LAYER_H_ */
